<!doctype html>
<html lang="zh-cn">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <link rel="shortcut icon" href="/favicon.ico" />
  <link href="/app/ai/css/bootstrap.min.css" rel="stylesheet">
  <script src="/app/ai/js/jquery.min.js"></script>
  <script src="/app/ai/js/bootstrap.bundle.min.js"></script>
  <title>webman AI助手</title>
</head>

<body class="bg-light ready sticky">
  <!-- CSS -->
  <link rel="stylesheet" href="/app/ai/css/app.css?v=v=<?=$css_version?>">

  <!-- webman ai 主应用 -->
  <div class="container-fluid h-100 d-flex bg-white" id="app">

    <!-- 对话列表 -->
    <div class="left-bar" v-show="showAddressBook" @click="hideAll">
      <div class="p-3 d-flex align-items-center">
        <input class="form-control form-control-sm bg-light" type="text" v-model="keyword" placeholder="搜索">
        <button class="btn btn-sm btn-light border ml-2 mr-0 f15 font-weight-bold" @click.stop="showRoleInfoBox"><span class="iconfont p-0">&#xe6a6;</span></button>
      </div>
      <div class="chat-list">
        <template v-for="item in filter">
          <div class="item" @click="switchRoleId(item.roleId)" :class="{selected: roleId==item.roleId, 'shadow-selected':contextMenu.roleId==item.roleId}" @contextmenu.prevent="openContextMenu(item.roleId, $event)">
            <div class="d-flex">
              <img class="avatar" :src="item.avatar" alt="avatar"/>
              <div class="ml-2">
                <div class="name">{{item.name}}</div>
                <div class="desc">{{item.desc}}</div>
              </div>
            </div>
            <div class="text-right text-secondary f12">
              <div style="height:1.3rem">{{formatDate(item.lastTime)}}</div>
              <div class="iconfont" v-if="item.pinned">&#xe677;</div>
            </div>
          </div>
        </template>
      </div>
      <div class="chat-list-footer text-secondary">
        <div class="iconfont f23 iconfont-bg" :class="{selected:box.showMore}" @click.stop="box.showMore=!showMore">&#xe6ed;</div>
      </div>
    </div>

    <!-- 聊天框 -->
    <div class="chat-box" :style="{width:showAddressBook?'calc(100% - 250px)':'100%'}" :class="{'slide-in': isSlidedIn, 'slide-out': isSlidedOut}" @click="hideAll" v-show="!isMobile || !showAddressBook">

      <div class="header d-flex justify-content-between" @click="scrollToTop()">
        <b class="iconfont" @click="slideOut" v-show="isMobile">&#xe6db;</b>
        <span>{{chat.name}}</span>
        <b class="iconfont" @click.stop="editRole(roleId)">⋯</b>
      </div>
      <div class="body">
        <ul class="list-unstyled overflow-auto h-100 mb-0 message-list" ref="messageBox">
          <template v-for="message in chat.messages">
            <li class="d-flex mt-4" :class="{'flex-row-reverse':message.role=='user'}">
              <img class="avatar" alt="avatar" :src="message.role!=='user'?chat.avatar:loginUser.avatar" width="40" height="40">
              <div class="position-relative d-flex align-items-center" @mouseenter="hoverMessageId=message.id" @mouseleave="hoverMessageId=0">
                <div class="card mx-2 markdown-body alert"
                     :class="{'alert-success':message.role==='user'}"
                     v-html="markdown(message.choices[0].delta.content)||(!message.completed?'<b class=\'animate-blink\'>|</b>':'')"
                >
                </div>
                <div class="p-1 bg-white rounded shadow-sm position-absolute" style="top:-20px;" v-show="hoverMessageId===message.id" :style="message.role==='user'?'left:0':'right:0'">
                  <span class="iconfont block-copy iconfont-bg" @click="copyToclipboard(message.choices[0].delta.content)"></span>
                  <span class="iconfont p-1 iconfont-bg" @click="deleteMessage(message.id)">&#xe680;</span>
                </div>
              </div>
            </li>
          </template>
        </ul>
        <div class="stop-btn">
          <button type="button" class="btn btn-sm btn-outline-secondary" v-show="chat.loading" @click="cancel" style="display: none">停止</button>
        </div>
      </div>
      <div class="footer" v-show="chat.name">
        <div class="tools" @click="scrollToBottom(true)">
          <span class="iconfont chat-tools-item iconfont-bg" title="通讯录" @click.stop="showAddressBook=!showAddressBook">&#xe6dc;</span>
          <span class="iconfont chat-tools-item iconfont-bg" title="清除消息" @click.stop="destroy">&#xe6a3;</span>
          <span class="iconfont chat-tools-item iconfont-bg" title="参数调整" :class="{selected:box.showParams}" @click.stop="showPanel('Params')">&#xe6e0;</span>
          <span class="iconfont chat-tools-item iconfont-bg f20" title="绑定ApiKey" :class="{selected:box.showApiKey}" @click.stop="showPanel('ApiKey')">&#xe627;</span>
          <span class="iconfont chat-tools-item float-right f20 d-none d-md-block iconfont-bg" title="发送方式" :class="{selected:box.showSendMethod}" @click.stop="showPanel('SendMethod')">&#xe696;</span>
        </div>
        <textarea class="input" :rows="!isMobile?6:2" placeholder="说点什么吧..." v-model="chat.content" @keypress="handleEnter"></textarea>
        <div class="send-btn d-flex align-items-center">
          <a href="https://www.workerman.net/app/view/ai" target="_blank" class="text-secondary" v-show="!isMobile&&showBuyLink" v-cloak>购买此程序</a>
          <button class="btn btn-sm btn-success px-3 ml-3" :disabled="chat.loading||!chat.content" @click="sendMessage">发送</button>
        </div>
      </div>
    </div>

    <div class="overlay bg-transparent" v-cloak v-show="showShadowLayer" @click="hideAll">
      <!-- 对话列表右键菜单 -->
      <div class="position-absolute shadow bg-white p-2 rounded cursor-pointer" @click.stop :style="{top:contextMenu.top+'px', left:contextMenu.left+'px'}" v-show="box.showContextMenu" v-cloak>
          <a class="dropdown-item iconfont" @click="pinRole()">&#xe677; 置顶</a>
          <a class="dropdown-item iconfont" @click="editRole()">&#xe681; 编辑</a>
          <a class="dropdown-item iconfont" @click="deleteRole()">&#xe680; 删除</a>
      </div>

      <!-- 参数设置 -->
      <div class="params-box shadow slide-up" @click.stop v-show="box.showParams" :style="{left:showAddressBook?'170px':'0'}" v-cloak>
        <div class="font-weight-bolder mt-1 mb-3">参数调整</div>
        <form v-if="chat.params">
          <div class="form-group row align-items-center">
            <label for="Model" class="col-sm-3 col-form-label">模型</label>
            <div class="col-sm-7">
              <select class="custom-select custom-select-sm" id="Model" v-model="chat.params.model">
                <option v-for="(name, value) in defaultModels" :value="value">{{name}}</option>
              </select>
            </div>
          </div>
          <div class="form-group row align-items-center">
            <label for="ContextNum" class="col-sm-3 col-form-label">上下文数</label>
            <div class="col-sm-7">
              <input type="range" class="custom-range" min="0" max="50" v-model="chat.params.contextNum">
            </div>
            <div class="col-sm-2">
              <input type="text" class="form-control form-control-sm" id="ContextNum" v-model="chat.params.contextNum">
            </div>
          </div>
          <div class="form-group row align-items-center">
            <label for="MaxTokens" class="col-sm-3 col-form-label">最大token数</label>
            <div class="col-sm-7">
              <input type="range" class="custom-range" min="1" max="4096" v-model="chat.params.maxTokens">
            </div>
            <div class="col-sm-2">
              <input type="text" class="form-control form-control-sm" id="MaxTokens" v-model="chat.params.maxTokens">
            </div>
          </div>
          <div class="form-group row align-items-center">
            <label for="Temperature" class="col-sm-3 col-form-label">创造性</label>
            <div class="col-sm-7">
              <input type="range" class="custom-range" min="0" max="1" step="0.1"  v-model="chat.params.temperature">
            </div>
            <div class="col-sm-2">
              <input type="text" class="form-control form-control-sm" id="Temperature" v-model="chat.params.temperature">
            </div>
          </div>
        </form>
      </div>

      <!-- ApiKey设置 -->
      <div class="api-key-box shadow slide-up pb-4" @click.stop v-show="box.showApiKey" style="width:400px" :style="{left:showAddressBook?'270px':'30px'}" v-cloak>
        <div class="font-weight-bolder mt-1 mb-3">使用自己的ApiKey</div>
        <div class="align-items-center d-flex">
          <div for="Model" class="col-form-label">ApiKey</div>
          <input class="form-control form-control-sm mx-2 bg-light" placeholder="sk-开头" id="ApiKey" v-model="apiKey" @blur="saveApiKey"/>
        </div>
      </div>

      <!-- 发送方式 -->
      <div class="send-method-box shadow" @click.stop v-show="box.showSendMethod" v-cloak>
        <a class="dropdown-item iconfont" @click="sendMethodSelect('Enter')" :class="{'alert-success':sendMethod=='Enter', selected:sendMethod=='Enter', 'pl-4': sendMethod!='Enter'}">Enter发送</a>
        <a class="dropdown-item iconfont" @click="sendMethodSelect('Ctrl-Enter')" :class="{'alert-success':sendMethod=='Ctrl-Enter', selected:sendMethod=='Ctrl-Enter', 'pl-4': sendMethod!='Ctrl-Enter'}">Ctrl+Enter发送</a>
      </div>

      <!-- 角色设置 -->
      <div class="center-box shadow slide-up" @click.stop v-show="box.showRoleInfo" v-cloak>
        <h4 class="mb-4">角色设置</h4>
        <form enctype="multipart/form-data" id="avatarForm" class="mb-3">
          <img :src="roleInfo.avatar" height="64" width="64" class="rounded-pill">
          <label class="btn btn-success btn-sm uploadBtn font-size-14 ml-4">
            上传头像
            <input type="file" name="avatar" id="avatar" class="d-none" accept="image/*" @change="uploadAvatar">
          </label>
        </form>
        <div class="form-group row align-items-center">
          <label for="name" class="col-sm-3 col-form-label">昵称</label>
          <div class="col-sm-9">
            <input type="text" class="form-control form-control-sm" id="name" v-model="roleInfo.name">
          </div>
        </div>
        <div class="form-group row align-items-center">
          <label for="desc" class="col-sm-3 col-form-label">简介</label>
          <div class="col-sm-9">
            <input type="text" class="form-control form-control-sm" id="desc" v-model="roleInfo.desc">
          </div>
        </div>
        <div class="form-group row align-items-center">
          <label for="greeting" class="col-sm-3 col-form-label">问候语</label>
          <div class="col-sm-9">
            <input type="text" class="form-control form-control-sm" id="greeting" v-model="roleInfo.greeting">
          </div>
        </div>
        <div class="form-group row align-items-center">
          <label for="rolePrompt" class="col-sm-3 col-form-label">角色指令</label>
          <div class="col-sm-9">
                <textarea class="form-control form-control-sm" id="rolePrompt" v-model="roleInfo.rolePrompt">
                </textarea>
          </div>
        </div>
        <div class="d-flex justify-content-center mt-4">
          <div>
            <button type="submit" class="btn btn-secondary" @click="hideAll">取消</button>
            <button type="submit" class="btn btn-success ml-2" @click="saveRole">保存</button>
          </div>
        </div>
      </div>

      <!-- AI信息 -->
      <div class="center-box shadow card p-0 overflow-hidden" @click.stop v-show="box.showSystemInfo" v-cloak>
          <img src="https://www.workerman.net/upload/img/20230327/276421479fb9e5.png">
          <div class="card-body">
            <h5 class="card-title">Webman AI助手</h5>
            <p class="card-text">Webman AI助手是一套基于webman开发的多角色ChatGPT聊天程序</p>
            <p class="card-text text-secondary">版本 <?=config('plugin.ai.app.version')?></p>
            <a href="https://www.workerman.net/app/view/ai" class="btn btn-success btn-sm" target="_blank">了解更多</a>
          </div>
      </div>

      <!-- 更多 -->
      <div class="more-box shadow border-top" @click.stop v-show="box.showMore" v-cloak :class="{'slide-up':box.showMore}">
        <a class="dropdown-item p-2 cursor-pointer" @click="resetSystem"><span class="iconfont f18">&#xe69f;</span>重置系统</a>
        <a class="dropdown-item p-2 cursor-pointer" @click="showPanel('SystemInfo')"><span class="iconfont f18">&#xe6de;</span>关于AI助手</a>
      </div>

    </div>

    <!-- 图片预览 -->
    <div class="overlay" style="display:none">
      <span class="close">&times;</span>
      <img alt="展示图片">
    </div>

  </div>

  <script>
    window.userAvatar = "<?=htmlspecialchars(session('user.avatar', ''))?>";
  </script>

  <!-- 代码高亮 -->
  <link rel="stylesheet" href="/app/ai/css/highlight.min.css">
  <script src="/app/ai/js/highlight.min.js"></script>

  <!-- markdown css -->
  <link rel="stylesheet" href="/app/ai/css/github-markdown.min.css">

  <!-- markdown -->
  <script src="/app/ai/js/markdown-it.min.js"></script>

  <!-- vue -->
  <script type="text/javascript" src="/app/ai/js/vue.global.js"></script>
  <script type="text/javascript" src="/app/ai/js/app.js?v=<?=$js_version?>"></script>

  <!-- 五彩纸屑效果 -->
  <script src="/app/ai/js/confetti.browser.min.js"></script>

</body>
</html>
